// ======================================================================
// Hell Lua Bus ( Lua Bind) Lib
// 
// Copyright 2013 Hell-Prototypes
//
// http://code.google.com/p/hell-prototypes/
//
// This is free software, licensed under the terms of the GNU General
// Public License as published by the Free Software Foundation.
// ======================================================================

#include <usb.h> /* libusb header */
//#include <unistd.h> /* for geteuid */
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

#include "define.h"

static union filedescriptor g_serial_fd;

#define UPM0    4
static int l_rs232_open(lua_State *L)
{
    int rs232_param_buf[1024];
    int data_len;
    int baudrate;
    //int data_bits;
    int parity;
    //int stop_bits;

    int UBRR, UCSRC = 0x06;//0x06 is reset value

    data_len = get_int_table_value(L, rs232_param_buf, sizeof(rs232_param_buf));

    if(data_len == 2) {
        baudrate = rs232_param_buf[0];
        parity = rs232_param_buf[1];//0:none, 1:odd, 2:even
        if((parity > 2)|| (parity < 0)) {
            parity = 0;
        }

        if(parity > 0) {
			if(parity == 1) {//odd
				UCSRC |= (3 << UPM0);
			} else {//even
				UCSRC = (UCSRC & (~(3 << UPM0))) | (2 << UPM0);
			}
		} else {
			UCSRC &= ~(3 << UPM0);
		}

        UBRR = (12000000/8/baudrate - 1) & 0x0fff;
	
        if(g_usb_dev != NULL) {
            if( usb_control_msg(g_usb_dev, 0x40, USB_RS232_OPEN, UBRR, UCSRC,
                                NULL, 0, 100) < 0) {
                lua_pushnumber (L, -ERR_CTRL_MSG);
            } else {
                lua_pushnumber (L, NO_ERR);
            }
        } else {
            lua_pushnumber (L, -ERR_NO_OPEN);
        }
    } else {
        lua_pushnumber (L, -ERR_PARAM);
    }

    return 1;
}

static int l_rs232_wr(lua_State *L)
{
    char wr_buf[1024*32];
    int data_len;

    data_len = get_byte_table_value(L, wr_buf, sizeof(wr_buf));

    if(data_len > 0) {
        if(g_usb_dev != NULL) {
            if( usb_control_msg(g_usb_dev, 0x40, USB_RS232_RW, 0x0000, 0x0000,
                                wr_buf, data_len, 3000) < 0) {
                lua_pushnumber (L, -ERR_CTRL_MSG);
            } else {
                lua_pushnumber (L, NO_ERR);
            }
        } else {
            lua_pushnumber (L, -ERR_NO_OPEN);
        }
    } else {
        lua_pushnumber (L, -ERR_PARAM);
    }

    return 1;
}

static int l_rs232_rd(lua_State *L)
{

    char rd_buf[1024*32];
    int rd_len, timeout, i;
    int top = lua_gettop(L);

    if(top != 2) {
        lua_pop(L, lua_gettop(L));//clear stack
        lua_pushnumber (L, -ERR_PARAM_NUM);
        return 1;
    }

    if(!lua_isnumber(L, -1)) {
        lua_pop(L, lua_gettop(L));//clear stack
        lua_pushnumber (L, -ERR_PARAM_TYPE);
        return 1;
    }
    timeout = lua_tointeger(L, -1);
    if(timeout < 0) {
        lua_pop(L, lua_gettop(L));//clear stack
        lua_pushnumber (L, -ERR_PARAM_TYPE);
        return 1;
    }

    if(!lua_isnumber(L, -2)) {
        lua_pop(L, lua_gettop(L));//clear stack
        lua_pushnumber (L, -ERR_PARAM_TYPE);
        return 1;
    }

    rd_len = lua_tointeger(L, -2);
    lua_pop(L, lua_gettop(L));//clear stack
    if((rd_len >= sizeof(rd_buf)) || (rd_len < 0)) {
        lua_pushnumber (L, rd_len);
        return 1;
    }

    if(g_usb_dev != NULL) {
        rd_len = usb_control_msg(g_usb_dev, 0x40 | 0x80, USB_RS232_RW, timeout, rd_len,
                                 rd_buf, rd_len, 3000);
        if(rd_len  < 0) {
            lua_pushnumber (L, -ERR_CTRL_MSG);
        } else {
            lua_newtable(L);
            for(i=0; i<rd_len; i++) {
                lua_pushinteger(L, (unsigned char)rd_buf[i] );
                lua_rawseti (L, -2, i+1);
            }
            return lua_gettop(L);
        }
    } else {
        lua_pushnumber (L, -ERR_NO_OPEN);
    }
    return 1;
}

static int l_rs232_close(lua_State *L)
{
    lua_pop(L, lua_gettop(L));//clear stack

    if(g_usb_dev != NULL) {
        if( usb_control_msg(g_usb_dev, 0x40, USB_RS232_CLOSE, 0x0000, 0x0000,
                            NULL, 0, 100) < 0) {
            lua_pushnumber (L, -ERR_CTRL_MSG);
        } else {
            lua_pushnumber (L, NO_ERR);
        }
    } else {
        lua_pushnumber (L, -ERR_NO_OPEN);
    }
    return 1;
}